#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <asm/uaccess.h>

MODULE_LICENSE("BSD");
MODULE_AUTHOR("Jared Candelaria");
MODULE_DESCRIPTION("Trivial");

#define MAX_LENGTH		sizeof(void *)

#define PROC_TRIVIAL		"trivial"
#define PROC_DO_NOT_READ	"do_not_read"

static struct proc_dir_entry *proc_trivial;
static struct proc_dir_entry *proc_do_not_read;
static void (*fp)(void);

int
file_write(struct file *file, const char __user *ubuf, unsigned long count, void *data)
{
	printk(KERN_INFO "trivial: called file_write\n");

	fp = NULL;

	if (count > MAX_LENGTH) {
		return -EFBIG;
	}
	if (copy_from_user(&fp, ubuf, count)) {
		return -EFAULT;
	}

	printk(KERN_INFO "trivial: fp: 0x%p\n", fp);

	return count;
}

int
file_read(char *page, char **start, off_t off, int count, int *eof, void *data)
{
	printk(KERN_INFO "trivial: called file_read\n");

	memcpy(page, &fp, sizeof(fp));

	if (fp != NULL)
		fp();

	printk(KERN_INFO "trivial: fp: 0x%p\n", fp);

	return sizeof(fp);
}

int __init
trivial_init(void)
{
	printk(KERN_INFO "trivial: loading module\n");

	proc_trivial = proc_mkdir(PROC_TRIVIAL, NULL);

	proc_do_not_read = create_proc_entry(PROC_DO_NOT_READ, 0666, proc_trivial);
	proc_do_not_read->read_proc = file_read;
	proc_do_not_read->write_proc = file_write;

	printk(KERN_INFO "trivial: created /proc/trivial entries\n");

	return 0;
}

void __exit
trivial_exit(void)
{
	printk(KERN_INFO "trivial: unloading module\n");

	remove_proc_entry(PROC_DO_NOT_READ, proc_trivial);
	remove_proc_entry(PROC_TRIVIAL, NULL);

	printk(KERN_INFO "trivial: removed /proc/trivial entries\n");
}

module_init(trivial_init);
module_exit(trivial_exit);
